Skip to content

fix(trampoline): don't set PYTHONHOME for venv trampolines#19123

Closed
Bojun-Vvibe wants to merge 2 commits intoastral-sh:mainfrom
Bojun-Vvibe:fix/astral-sh-uv-19080
Closed

fix(trampoline): don't set PYTHONHOME for venv trampolines#19123
Bojun-Vvibe wants to merge 2 commits intoastral-sh:mainfrom
Bojun-Vvibe:fix/astral-sh-uv-19080

Conversation

@Bojun-Vvibe
Copy link
Copy Markdown

Closes #19080

Repo

astral-sh/uv

Issue

#19080

Root cause

The Windows trampoline in crates/uv-trampoline/src/bounce.rs decides whether to
set PYTHONHOME by calling is_virtualenv(python_exe). For a venv trampoline,
python_exe resolves to the base managed interpreter (e.g.
~\AppData\Roaming\uv\python\cpython-3.13-...\python.exe), which is not itself
a virtualenv. So even when the user invokes .venv\Scripts\python (which IS a
venv trampoline), PYTHONHOME is set to the base install. That env var then
leaks to child processes (e.g. cibuildwheel running a different Python),
shadowing the wrong stdlib and producing
AttributeError: module '_thread' has no attribute 'start_joinable_thread'.

Fix

Also check is_virtualenv(executable_name) — the trampoline's own path — before
deciding to set PYTHONHOME. A venv trampoline lives in <venv>\Scripts\ next
to a <venv>\pyvenv.cfg, so this correctly suppresses PYTHONHOME for venv
trampolines while preserving the original junction-handling behavior for
non-venv managed interpreters.

Regression test

None added. The trampoline crate (crates/uv-trampoline) is excluded from the
workspace, builds only as a Windows binary with panic-immediate-abort /
#![no_main], and has no existing unit-test surface. The patch is a
two-line guard change adjacent to the existing is_virtualenv(python_exe)
check and follows the same pattern.

Risk

low

Verification

skipped: build requires Windows MSVC toolchain (cross-check on macOS fails on
rust-src for the nightly toolchain). The change is a localized predicate
extension reusing the existing is_virtualenv helper.

The PYTHONHOME env var was set whenever the resolved `python_exe` was
not itself a virtualenv, but for venv trampolines `python_exe` is the
base interpreter outside the venv. The check now also inspects the
trampoline's own location, so venvs built on managed interpreters no
longer leak PYTHONHOME pointing at the base install into child
processes (which could mix stdlib across Python versions).
@zanieb
Copy link
Copy Markdown
Member

zanieb commented Apr 23, 2026

This seems vaguely correct, though we may want to remove the PYTHONHOME setting entirely cc @geofft this may be a safer intermediate change.

// - Override inherited `PYTHONHOME` from parent Python processes
// - Preserve user-defined `PYTHONHOME` values
if !is_virtualenv(python_exe.as_path()) {
//
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test-windows-trampolines / check on * CI jobs are failing. Per the workflow, these run cargo fmt --check and cargo clippy --all-features --target x86_64-pc-windows-msvc --tests -- -D warnings.

Please run:

cd crates/uv-trampoline
cargo fmt
cargo clippy --all-features --target x86_64-pc-windows-msvc --tests -- -D warnings

Then push the formatting fixes.

@geofft
Copy link
Copy Markdown
Contributor

geofft commented Apr 23, 2026

I'm taking a deeper look at this and I do want to try to unset PYTHONHOME in more cases. I may end up opening a separate PR for that.

@Bojun-Vvibe
Copy link
Copy Markdown
Author

Thanks for the quick look @zanieb @geofft. Happy to defer to your judgment on the broader PYTHONHOME cleanup — if a more comprehensive change in a separate PR is preferable, feel free to close this one or just let me know and I'll close it. Otherwise this can stand as the minimal intermediate fix.

Signed-off-by: Bojun Chai <bojunchai@microsoft.com>
@Bojun-Vvibe
Copy link
Copy Markdown
Author

Thanks for the pointer! Pushed cargo fmt fix in 1000b9c. The change is single-file and trivial (line-length wrap), so I expect test-windows-trampolines / check to go green; will run cargo clippy --all-features --target x86_64-pc-windows-msvc --tests -- -D warnings via cargo-xwin if anything else surfaces.

@geofft
Copy link
Copy Markdown
Contributor

geofft commented Apr 27, 2026

So the issue with this (which I admit I had to have Claude remind me of, though I should have suspected it myself) is that it doesn't work right on Python 3.10 and below. The older C-based implementation of getpath used up to 3.10 gets confused when you set __PYVENV_LAUNCHER__ to a non-venv trampoline but you don't also set PYTHONHOME to the underlying installation. In other words this PR as written breaks .local\bin\python3.10.exe, although it doesn't break a Python 3.10 venv.

However, you don't actually need to set __PYVENV_LAUNCHER__ either in that case, which solves the problem. So what you actually want to do (I think) is to make setting __PYVENV_LAUNCHER__ conditional on the target being a venv and ditch all the PYTHONHOME code. I've opened #19199 to take that approach. Appreciate the enthusiasm and promptness with this, though!

@Bojun-Vvibe
Copy link
Copy Markdown
Author

Thanks for the careful read and for catching the 3.10 getpath behavior — your conditional-on-venv approach in #19199 is cleaner and avoids the PYTHONHOME plumbing entirely. Closing this in favor of yours.

@Bojun-Vvibe
Copy link
Copy Markdown
Author

Superseded by #19199 (better approach).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

uv 0.11.7 with 3.13 interpreter on windows fails to build python wheel for cp311/cp312 using cibuildwheel

5 participants